use std::collections::HashMap;

use libloading::Symbol;

use common_base::{
    prelude::*,
    serde::{self, Deserialize},
};

use crate::{
    service_engine::service_model::ServicePluginCreator, support::DylibRepository, ServicePlugin,
};

#[derive(Deserialize, Debug)]
#[serde(crate = "self::serde")]
#[serde(rename_all = "camelCase")]
pub struct ServicePluginStub {
    comp_creator: String,
    #[serde(rename = "iD")]
    id: String,
    name: String,
    enabled: bool,
    #[serde(rename = "rollBackService")]
    rollback_service: Option<String>,
    property_map: HashMap<String, String>,
}

impl ServicePluginStub {
    pub fn load_service_plugin(
        self,
        dylib_repository: &DylibRepository,
    ) -> Result<Box<dyn ServicePlugin>> {
        let dylib_and_func = self.comp_creator.split("::").collect::<Vec<&str>>();
        if dylib_and_func.len() != 2 || dylib_and_func[0].is_empty() || dylib_and_func[1].is_empty()
        {
            return Err(ErrorCode::DylibLoadFailed(format!(
                "ServicePluginStub[{}] comp_creator format error, should be `dylib_name::creator_func_name`, but is {}.",
                self.id,
                self.comp_creator
            )));
        }
        let mut service_plugin = unsafe {
            let _guard = dylib_repository.get_or_create(dylib_and_func[0])?;
            let func: Symbol<ServicePluginCreator> =
                _guard.value().get(dylib_and_func[1].as_bytes())?;
            *Box::from_raw(func())
        };
        info!("load {} successed", dylib_and_func[1]);

        let base = service_plugin.get_service_plugin_base_mut();
        base.id = self.id;
        base.name = self.name;
        base.enabled = self.enabled;
        base.rollback_service = self.rollback_service;
        base.property_map = self.property_map;

        Ok(service_plugin)
    }
}
